package sk.naive.talker.persistence;

import sk.naive.talker.util.Utils;

import java.sql.*;
import java.util.logging.Logger;

/**
 * DbTransaction.
 *
 * @author <a href="mailto:virgo@naive.deepblue.sk">Richard "Virgo" Richter</a>
 * @version $Revision: 1.2 $ $Date: 2005/02/20 13:27:52 $
 */
public class DbTransaction {
	private static Logger logger = Logger.getLogger("nt.dbLayer");

	private static DbConnectionPool connectionPool;
	private static ThreadLocal<Connection> connectionThreadLocal = new ThreadLocal<Connection>();
	private static ThreadLocal<String> rollbackOnly = new ThreadLocal<String>();
	private static Connection nonTransactionConnection;

	public static void init(DbConnectionPool connectionPool) throws PersistenceException {
		DbTransaction.connectionPool = connectionPool;
		try {
			nonTransactionConnection = connectionPool.getRealConnection(true);
		} catch (SQLException e) {
			throw new PersistenceException(e);
		}
		logger.info("DbTransaction system initialized");
	}

	public static void begin() throws PersistenceException {
		if (connectionThreadLocal.get() != null) {
			throw new PersistenceException("There is already running transaction on connection " + connectionThreadLocal.get());
		}
		Connection connection = connectionPool.getConnection();
		connectionThreadLocal.set(connection);
		rollbackOnly.set(null);
		logger.finest("Transaction begin on connection " + connection);
	}

	public static Connection getConnection() {
		Connection conn = connectionThreadLocal.get();
		if (conn == null) {
			conn = nonTransactionConnection;
		}
		return conn;
	}

	public static void finish() throws PersistenceException {
		Connection conn = connectionThreadLocal.get();
		logger.finest("Transaction finish on connection " + conn);
		if (conn == null) {
			throw new PersistenceException("There is no running transaction at this time!");
		}
		try {
			if (rollbackOnly.get() != null) {
				conn.rollback();
				logger.info("Rolling back transaction on connection " + conn + " - reason: " + rollbackOnly.get());
			} else {
				conn.commit();
			}
		} catch (SQLException e) {
			throw new PersistenceException(e);
		} finally {
			releaseConnection();
		}
	}

	private static void releaseConnection() throws PersistenceException {
		connectionPool.releaseConnection(connectionThreadLocal.get());
		connectionThreadLocal.set(null);
	}

	public static void setRollbackOnly(String reason) {
		logger.finest("Setting rollback only for transaction on connection " + connectionThreadLocal.get());
		rollbackOnly.set(reason);
	}

	public static void finishWithoutException() {
		try {
			finish();
		} catch (PersistenceException e) {
			Utils.unexpectedExceptionWarning(e);
		}
	}
}
